package com.thinkingcoder.tccache.core.operator;

import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Random;

import com.thinkingcoder.tccache.core.model.CacheEntry;

/**
 * Set operator.
 */
public class SetOperator extends AbstractOperator {

    Random random = new Random();

    public Integer sAdd(String key, String[] vals) {
        CacheEntry<?> cacheEntry = getOrInitCacheEntry(key);

        LinkedHashSet<String> exist = (LinkedHashSet<String>)cacheEntry.getValue();

        return vals == null ? 0 : (int)Arrays.stream(vals).map(exist::add).filter(x -> x).count();
    }

    public String[] sMembers(String key) {
        if (checkInvalid(key)) {
            return null;
        }

        LinkedHashSet<String> exist = getSetEntryValue(key);
        return exist == null ? null : exist.toArray(new String[0]);
    }

    public int sCard(String key) {
        if (checkInvalid(key)) {
            return 0;
        }

        LinkedHashSet<?> exist = getSetEntryValue(key);
        return exist == null ? 0 : exist.size();
    }

    public Integer sIsMember(String key, String value) {
        if (checkInvalid(key)) {
            return 0;
        }

        LinkedHashSet<String> exist = getSetEntryValue(key);
        return exist == null ? 0 : exist.contains(value) ? 1 : 0;
    }

    public Integer sRem(String key, String[] values) {
        if (checkInvalid(key) || values == null || values.length == 0) {
            return 0;
        }

        LinkedHashSet<String> exist = getSetEntryValue(key);
        return exist == null ? 0 : (int)Arrays.stream(values).map(exist::remove).filter(x -> x).count();
    }

    public String[] sPop(String key, int count) {
        if (checkInvalid(key)) {

        }

        LinkedHashSet<String> exists = getSetEntryValue(key);
        if (exists == null) {
            return null;
        }
        int len = Math.min(exists.size(), count);
        String[] ret = new String[len];
        for (int idx = 0; idx < len; idx++) {
            String[] array = exists.toArray(new String[0]);
            String obj = array[random.nextInt(exists.size())];
            exists.remove(obj);
            ret[idx] = obj;
        }
        return ret;
    }

    private CacheEntry<?> getOrInitCacheEntry(String key) {
        CacheEntry<?> cacheEntry = getCacheEntry(key);
        if (cacheEntry == null) {
            synchronized (getMap()) {
                if ((cacheEntry = getCacheEntry(key)) == null) {
                    cacheEntry = new CacheEntry<>(new LinkedHashSet<String>(), System.currentTimeMillis(), -1000L);
                    putCacheEntry(key, cacheEntry);
                }
            }
        }
        return cacheEntry;
    }

    private LinkedHashSet<String> getSetEntryValue(String key) {
        return (LinkedHashSet<String>)getCacheEntryValue(key);
    }

}
